require 'json'

module SerialBox

  # Container module for all {SerialBox} serializers.

  module Serializers

    # JSON adapter for {SerialBox}. Defines the following methods when included
    # in a class:
    #
    # * `#as_json`
    # * `#to_json`
    # * `.json_create`
    #
    # This gives the class total ability to work with `JSON.parse` and
    # `#to_json`.

    module JSON
      extend ActiveSupport::Concern

      # @private
      JSON_CREATE_ID = JSON.respond_to?(:create_id) ? JSON.create_id : 'json_class'

      # Converts this object into primitives suitable for JSON serialization.
      #
      # @return [Hash, Array] A JSON-serializable object.

      def as_json(*)
        hsh = {SerialBox::Serializers::JSON::JSON_CREATE_ID => self.class.name}
        self.class._serialbox_serializer.serialization_operations.each do |operation|
          operation.apply self, hsh
        end
        return hsh
      end

      # Serializes this object as JSON.
      #
      # @return [String] The JSON representation of this object.

      def to_json(*args) as_json.to_json(*args) end

      module ClassMethods

        # Converts a primitive object (deserialized from JSON) into an instance
        # of this class.
        #
        # **Note:** You should not call this method directly. You should use
        # `JSON.parse` to ensure recursive deserialization works properly.
        #
        # @param [Array, Hash] object The JSON-ready primitive represnetation of
        #   an instance of this class.
        # @return An instance of this class derived from the JSON.

        def json_create(object)
          instance = allocate
          _serialbox_serializer.deserialization_operations.each do |operation|
            operation.apply instance, object
          end
          return instance
        end
      end
    end
  end
end
